package cn.team.config;

import com.fasterxml.jackson.databind.ObjectMapper;

import cn.team.filter.JsonUsernamePasswordAuthenticationFilter;
import cn.team.service.UserDetailServiceImpl;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.servlet.ServletOutputStream;
import java.util.HashMap;
import java.util.Map;

@EnableWebSecurity
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public UserDetailsService userDetailsService() {
        return new UserDetailServiceImpl();
    }

    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    UsernamePasswordAuthenticationFilter usernamePasswordAuthenticationFilter() throws Exception {
        JsonUsernamePasswordAuthenticationFilter jsonUsernamePasswordAuthenticationFilter = new JsonUsernamePasswordAuthenticationFilter();
        jsonUsernamePasswordAuthenticationFilter.setFilterProcessesUrl("/login");
        jsonUsernamePasswordAuthenticationFilter.setAuthenticationSuccessHandler(
                (request, response, authentication) -> {
                    response.setContentType("application/json;charset=utf-8");
                    ObjectMapper objectMapper = new ObjectMapper();
                    Map<String, Object> result = new HashMap<>();
                    result.put("status", HttpStatus.OK);
                    result.put("msg", "ok");
                    result.put("userInfo",authentication.getPrincipal());
                    result.put("authentication", authentication.getDetails());
                    ServletOutputStream os = response.getOutputStream();
                    objectMapper.writeValue(os, result);
                    os.flush();
                    os.close();
                });
        jsonUsernamePasswordAuthenticationFilter.setAuthenticationManager(authenticationManagerBean());
        jsonUsernamePasswordAuthenticationFilter.setPasswordParameter("password");
        jsonUsernamePasswordAuthenticationFilter.setUsernameParameter("username");
        jsonUsernamePasswordAuthenticationFilter.setAuthenticationFailureHandler(((request, response, exception) -> {
            response.setContentType("application/json;charset=utf-8");
            response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
            ObjectMapper objectMapper = new ObjectMapper();
            Map<String, Object> result = new HashMap<>();
            result.put("status", HttpStatus.OK);
            result.put("msg", "err");
            result.put("authentication", exception.getStackTrace());
            ServletOutputStream os = response.getOutputStream();
            objectMapper.writeValue(os, result);
            os.flush();
            os.close();
        }));

        return jsonUsernamePasswordAuthenticationFilter;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder());
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.authorizeHttpRequests()
                .mvcMatchers("/vc.jpg", "/login", "/chat/**","/file/**","/**")
                .permitAll()
                .anyRequest()
                .authenticated();

        http.formLogin();

        http.exceptionHandling(handling -> handling
                .authenticationEntryPoint(((request, response, authException) -> {
                    response.setContentType("application/json;charset=utf-8");
                    response.setStatus(HttpStatus.UNAUTHORIZED.value());
                    response.getWriter().println("尚未登录认证，无法请求资源，请认证后再来！");
                })));

        http.csrf(AbstractHttpConfigurer::disable);

        http.cors();

        http.addFilterAt(usernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.ALWAYS);
    }
}
